Skip to content

2、EnvoyFilter API

EnvoyFilter API

目录

[toc]

本节实战

实战名称
🚩 实战:EnvoyFilter API-全局范围-2023.12.18(测试成功)
🚩 实战:EnvoyFilter API-配置优先级-2023.12.18(测试成功)
🚩 实战:EnvoyFilter API-添加 Lua 脚本-2023.12.18(测试成功)

EnvoyFilter API

前面我们介绍了可以使用 EnvoyFilter对象来部署 Istio Wasm 插件,此外 EnvoyFilter还可以实现很多其他的功能。EnvoyFilter提供了一种机制来自定义 Istio Pilot 生成的 Envoy 配置,使用 EnvoyFilter 可以修改某些字段的值、添加特定过滤器,甚至添加全新的侦听器、集群等,当然我们必须谨慎使用此功能,因为不正确的配置可能会破坏整个网格的稳定性。

需要注意当多个 EnvoyFilter绑定到指定命名空间中的相同工作负载时,所有补丁将按照创建时间的顺序依次处理,如果多个 EnvoyFilter配置相互冲突,则会无效。要将 EnvoyFilter资源应用于系统中的所有工作负载(sidecar 和网关),则根命名空间中定义该资源,而不使用工作负载选择器即可。

Patch 操作

EnvoyFilter对象中有一个 configPatches字段,这个字段属于核心字段,用于指定要对 Envoy 进行什么样的操作,对各种配置对象进行的更改,该字段下面主要包括三个字段:

  • applyTo:指定应在 Envoy 配置中的哪个位置应用补丁。根据 applyTo 的不同,匹配条件应选择相应的对象。例如,带有HTTP_FILTER的 applyTo 应该在监听器上有一个匹配条件,网络过滤器选择 envoy.filters.network.http_connection_manager,并在相对于插入应执行的 HTTP 过滤器上有一个子过滤器选择。类似地,对于 CLUSTER的 applyTo,如果提供了匹配条件,应该在集群上匹配,而不是在监听器上。
  • match:在监听器/路由配置/集群上的匹配。
  • patch:要应用的补丁以及操作。

其中的 applyTo指定了在 Envoy 配置中给定的补丁应该被应用的位置,这个字段的值可以使用的值如下所示:

名称描述
INVALID
LISTENER将补丁应用于监听器。
FILTER_CHAIN将补丁应用于过滤器链。
NETWORK_FILTER将补丁应用于网络过滤器链,以修改现有过滤器或添加新过滤器。
HTTP_FILTER将补丁应用于 HTTP 连接管理器中的 HTTP 过滤器链,以修改现有过滤器或添加新过滤器。
ROUTE_CONFIGURATION将补丁应用于 HTTP 连接管理器内的路由配置(rds 输出)。这不适用于虚拟主机。目前,仅允许在路由配置对象上进行MERGE操作。
VIRTUAL_HOST将补丁应用于路由配置中的虚拟主机。
HTTP_ROUTE将补丁应用于路由配置中匹配的虚拟主机内的路由对象。
CLUSTER将补丁应用于 CDS 输出中的集群。也用于添加新集群。
EXTENSION_CONFIG将补丁应用于或在 ECDS 输出中添加扩展配置。注意,ECDS 仅由 HTTP 过滤器支持。
BOOTSTRAP将补丁应用于引导配置。
LISTENER_FILTER将补丁应用于监听器过滤器。

根据我们的需求选择不同的 applyTo值,然后在 match字段中指定匹配条件,在将补丁应用于给定代理的生成配置之前,必须满足一个或多个匹配条件,match下面可以配置的字段如下所示:

  • context:匹配特定的配置的生成上下文。Istio Pilot 在网关的上下文中、sidecar 的入站流量和出站流量中生成 envoy 配置。可以配置的包括:

    • ANY:Sidecar 和网关中的所有侦听器/路由/集群。
    • SIDECAR_INBOUND:Sidecar 中的入站侦听器/路由/集群。
    • SIDECAR_OUTBOUND:Sidecar 中的出站侦听器/路由/集群。
    • GATEWAY:网关中的侦听器/路由/集群。
  • proxy:匹配与代理关联的属性。

  • listener:匹配 envoy 监听器属性。

  • routeConfiguration:匹配 envoy HTTP 路由配置属性。

  • cluster:匹配 envoy 集群属性。

最后的 patch字段用于指定要应用的补丁以及操作,这个字段的值可以使用的值如下所示:

  • operation:指定 path 应该如何被应用,可以配置的值包括:

    • INVALID:无效的操作。
    • MERGE:将补丁与现有配置合并,如果要指定整个配置,请使用用 REPLACE
    • ADD:将提供的配置添加到现有列表中(侦听器、集群、虚拟主机、网络过滤器或 HTTP 过滤器)。当 applyTo设置为 ROUTE_CONFIGURATIONHTTP_ROUTE时,此操作将被忽略。
    • REMOVE:从列表(侦听器、集群、虚拟主机、网络过滤器、路由或 http 过滤器)中删除选定的对象,不需要指定 value。当 applyTo设置为 ROUTE_CONFIGURATIONHTTP_ROUTE时,此操作将被忽略。
    • INSERT_BEFORE:在指定的对象之前插入提供的配置。此操作通常仅在过滤器或路由的上下文中有用,其中元素的顺序很重要。路由应根据最具体的匹配条件进行排序,因为会选择第一个匹配的元素。对于集群和虚拟主机,数组中的元素的顺序并不重要。在选择的过滤器或子过滤器之前插入。如果未选择任何过滤器,则指定的过滤器将插入到列表的最前面。
    • INSERT_AFTER:在指定的对象之后插入提供的配置。
    • INSERT_FIRST:根据所选的过滤器的存在与否,在列表中首先进行插入。当您希望根据 Match 子句中指定的匹配条件将您的过滤器排在列表的第一位时,这特别有用。
    • REPLACE:用新内容替换过滤器的内容。REPLACE操作仅适用于 HTTP_FILTERNETWORK_FILTER
  • value:指定要应用的补丁,被修补的对象的 JSON 配置。将使用 proto 合并语义与路径中现有的 proto 进行合并。

  • filterClass:确定过滤器插入顺序,它与 ADD操作结合使用,如果您的过滤器依赖于或影响过滤器链中另一个过滤器的功能,则过滤器排序非常重要。在过滤器类中,过滤器按照处理顺序插入。可以配置的值包括:

    • UNSPECIFIED:控制平面决定在哪里插入过滤器,如果过滤器独立于其他过滤器,则不要指定 FilterClass
    • AUTHN:在 Istio 身份验证过滤器之后插入过滤器。
    • AUTHZ:在 Istio 授权过滤器之后插入过滤器。
    • STATS:在 Istio 统计过滤器之前插入过滤器。

接下来我们就用几个例子再来熟悉下 EnvoyFilter的使用。

全局范围

🚩 实战:EnvoyFilter API-全局范围-2023.12.18(测试成功)

  • 测试环境
bash
k8sv1.27.6(containerd:istiov1.19.3(--setprofile=demo)tinygoversion0.30.0

实验软件:

链接:https:apiVersion:networking.istio.io/v1alpha3kind:EnvoyFiltermetadata:name:access-lognamespace:istio-systemspec:configPatches:- applyTo:NETWORK_FILTERmatch:listener:filterChain:filter:name:"envoy.filters.network.http_connection_manager"patch:operation:MERGEvalue:typed_config:"@type":"type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager"access_log:- name:envoy.access_loggers.filetyped_config:"@type":"type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog"path:/dev/stdoutlog_format:text_format:"[%START_TIME%] \"%RESPONSE_CODE% \n"

在上面的这个资源对象中我们重新定义了 Envoy 的的访问日志,将日志输出到标准输出中,并重新定义了日志的格式。

从上面的结果可以看到,我们通过 EnvoyFilter 自定义的日志已经生效了。

如果设置一个其他的命名空间,比如 default,那么这个 EnvoyFilter就只会应用到 default命名空间中的工作负载,而不会应用到其他命名空间中的工作负载。同样再次加上工作负载选择器,那么这个 EnvoyFilter就只会应用到 default命名空间中特定的工作负载了,而不会应用到工作负载。

测试结束。😘

配置优先级

🚩 实战:EnvoyFilter API-配置优先级-2023.12.18(测试成功)

  • 测试环境
bash
k8sv1.27.6(containerd:istiov1.19.3(--setprofile=demo)tinygoversion0.30.0

实验软件:

链接:https:apiVersion:networking.istio.io/v1alpha3kind:EnvoyFiltermetadata:name:priority-20spec:workloadSelector:labels:app:productpagepriority:20configPatches:- applyTo:HTTP_FILTERmatch:context:ANYlistener:filterChain:filter:name:"envoy.filters.network.http_connection_manager"subFilter:name:"envoy.filters.http.fault"patch:operation:MERGEvalue:name:envoy.filters.http.faulttyped_config:"@type":type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFaultabort:http_status:503percentage:numerator:100denominator:HUNDRED

在上面的这个资源对象中我们定义了一个 EnvoyFilter,这个 EnvoyFilter的优先级为 20,我们将会在 Productpage 服务中应用这个 EnvoyFilter,这个 EnvoyFilter的作用是在 Productpage 服务中添加一个故障注入的过滤器,当我们访问 Productpage 服务时,会全部返回 503 错误。

这个资源对象和前面的资源对象基本一样,只是将优先级设置为 10,另外将故障注入的概率都设置为 50%, 并且中断的状态码为 500。

从结果看每次请求都会返回 503 错误,这是因为优先级为 10 的 EnvoyFilter先于优先级为 20 的 EnvoyFilter应用,所以优先级为 20 的 EnvoyFilter覆盖了优先级为 10 的 EnvoyFilter,这也是符合我们的预期的。

测试结束。😘

添加 Lua 脚本

🚩 实战:EnvoyFilter API-添加 Lua 脚本-2023.12.18(测试成功)

  • 测试环境
bash
k8sv1.27.6(containerd:istiov1.19.3(--setprofile=demo)tinygoversion0.30.0

实验软件:

链接:https:apiVersion:networking.istio.io/v1alpha3kind:EnvoyFiltermetadata:name:productpage-luanamespace:defaultspec:workloadSelector:labels:app:productpageconfigPatches:# 第一个 patch 将 lua 过滤器添加到监听器/HTTP连接管理器中。- applyTo:HTTP_FILTER# HTTP_FILTER 用于 HTTP 连接管理器中的 HTTP 过滤器链match:context:SIDECAR_INBOUNDlistener:portNumber:9080filterChain:filter:name:"envoy.filters.network.http_connection_manager"subFilter:name:"envoy.filters.http.router"patch:operation:INSERT_BEFOREvalue:# lua filter specificationname:envoy.filters.http.luatyped_config:"@type":"type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"defaultSourceCode:inlineString:|function envoy_on_response(response_handle)response_handle:headers():add("lua-filter","true")response_handle:headers():add("website","youdianzhishi.com")endfunction envoy_on_request(request_handle)-- 发起 HTTP 调用到 lua_cluster (即 baidu.com),并附加搜索词local response_headers,response_body =request_handle:httpCall("lua_cluster",{[":method"] ="GET",[":path"] ="/s?wd=优点知识",[":authority"] ="baidu.com"},"",5000)-- 使用 baidu.com 的搜索结果作为原始请求的响应request_handle:respond(response_headers,response_body)end# 第二个 path 需要添加上面 lua 脚本里面指定的 lua_cluster 集群- applyTo:CLUSTERmatch:context:SIDECAR_OUTBOUNDpatch:operation:ADDvalue:# cluster specificationname:"lua_cluster"type:STRICT_DNSconnect_timeout:0.5slb_policy:ROUND_ROBINload_assignment:cluster_name:lua_clusterendpoints:- lb_endpoints:- endpoint:address:socket_address:protocol:TCPaddress:"baidu.com"port_value:80

上面的资源对象中我们定义了两个 patch,第一个用于将 lua 过滤器添加到监听器/HTTP 连接管理器中,并添加上 Lua 代码,第二个补丁用于添加 lua_cluster集群。

envoy_on_request这是一个定义在 Envoy 的 Lua 环境中的函数,它在请求被处理时被调用。这个函数名是 Envoy 约定的特定名称,Envoy 会在处理请求时自动调用这个函数。

img

在上面的结果中可以看到我们添加的 Lua 过滤器:

img

正常可以看到如下所示的结果:

img

除此之外还有非常多的使用场景,总之,只要能够通过 Envoy 的配置来实现的,都可以通过 EnvoyFilter来实现。

测试结束。😘

作业

假设有一个需求是有好几万的租户在使用一个云服务,这个云服务会自动为所有的租户分配一个二级域名,配置 HTTPS 证书,这个场景我们直接通过 Gateway API 里面配置一个通配符的域名和对应的证书是不是就可以了。

现在的需求是有很多用户有自定义域名的一个需求,也需要支持这些用户配置证书,由于现在的 443 端口已经被通用的 Gateway 对象占用了,所以不能为每一个租户添加一个 Gateway API,那么应该如何使用同一个 Gateway API 来支持通配符的证书以及用户自定义的域名和证书的配置呢?

直接在 Gateway API 里面是不是加上这些自定义的域名和证书就可以了?确实可以,但是这个功能是开放给用户去使用的,这样的话是不是就会对其他用户可能产生影响,肯定是不希望用户能够去更新 Gateway API 对象的,那么这个时候应该如何实现呢?

不希望修改 Gateway API 对象,就能够支持很多用户的自定义域名和证书的需求(使用同一个 443 端口)?

使用我们今天讲的 EnvoyFilter 是不是就可以可以了?一个租户去自定义域名或者证书的时候单独就创建一个 EnvoyFilter 是不是就可以了(针对 Gateway)。

关于我

我的博客主旨:

  • 排版美观,语言精炼;
  • 文档即手册,步骤明细,拒绝埋坑,提供源码;
  • 本人实战文档都是亲测成功的,各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人帮您解决问题,让我们一起进步!

🍀 微信二维码 x2675263825 (舍得), qq:2675263825。

image-20230107215114763

🍀 微信公众号 《云原生架构师实战》

image-20230107215126971

🍀 个人博客站点

http:

版权:此文章版权归 One 所有,如有转载,请注明出处!

链接:可点击右上角分享此页面复制文章链接

上次更新时间:

最近更新